/**
 * 实例管理器 - 负责管理单个Electron应用实例及其配对的后端服务
 * 模式：后端服务自主分配端口，并通过STDOUT通知Electron主进程，主进程再通过IPC推送给渲染进程。
 */
import fs from 'fs'
import path from 'path'
import { app, dialog, WebContents } from 'electron'
import { spawn, exec, ChildProcess } from 'child_process'
import http from 'http'

// 接口定义
export interface PortConfig {
  masterPort: number
  childPort: number
  websocketPort: number
}

export interface InstanceInfo {
  electronPid: number
  backendPid: number | null
  ports: PortConfig | null
  startTime: string
}

interface InstanceFile {
  instances: InstanceInfo[]
  lastUpdated: string
}

// 常量
const MAX_INSTANCES = 3
const INSTANCE_FILE_PATH = path.join(app.getPath('userData'), 'instances.json')
const MAX_RESTART_ATTEMPTS = 5
const BASE_RESTART_DELAY = 3000 // ms
const HEALTH_CHECK_INTERVAL = 30000 // ms
const HEALTH_CHECK_TIMEOUT = 5000 // ms

export class InstanceManager {
  private instanceInfo: InstanceInfo | null = null
  private backendProcess: ChildProcess | null = null
  private isStopping = false
  private restartCount = 0
  private healthCheckTimer: NodeJS.Timeout | null = null
  private webContents: WebContents | null = null // <--- 新增：存储webContents

  constructor() {
    this.cleanDeadInstances();
    
    // 注册进程退出时的清理函数
    process.on('exit', () => {
      if (this.backendProcess && !this.backendProcess.killed) {
        console.log('主进程退出，强制终止后端进程')
        try {
          if (process.platform === 'win32') {
            require('child_process').execSync(`taskkill /F /T /PID ${this.backendProcess.pid}`)
          } else {
            this.backendProcess.kill('SIGKILL')
          }
        } catch (error) {
          console.error('强制终止后端进程失败:', error)
        }
      }
    })
    
    // 处理未捕获的异常
    process.on('uncaughtException', (error) => {
      console.error('未捕获的异常:', error)
      this.shutdownBackend().finally(() => {
        process.exit(1)
      })
    })
  }

  // --- Public API ---

  public async startBackend(webContents: WebContents): Promise<boolean> {
    this.webContents = webContents;

    const instances = this.readInstanceFile();
    if (instances.length >= MAX_INSTANCES) {
      dialog.showErrorBox('启动限制', `最多只能同时运行 ${MAX_INSTANCES} 个应用实例。`);
      return false;
    }

    if (this.backendProcess) {
      console.log('后端服务已在运行中，跳过。');
      return true;
    }

    this.instanceInfo = this.registerInstance(); // 注册实例并获取实例信息
    if (!this.instanceInfo) {
      return false; // 注册失败，可能是达到了实例上限
    }
    this.spawnBackendProcess();
    this.setupProcessListeners();
    return true;
  }

  public async shutdownBackend(): Promise<void> {
    if (this.isStopping) return
    this.isStopping = true
    console.log('开始关闭后端服务...')
    this.stopHealthMonitoring()
    
    if (this.backendProcess && !this.backendProcess.killed) {
      console.log(`正在终止后端进程 PID: ${this.backendProcess.pid}`)
      
      // 首先尝试优雅关闭
      try {
        this.backendProcess.kill('SIGTERM')
        await new Promise(resolve => setTimeout(resolve, 2000)) // 等待2秒
      } catch (error) {
        console.log('优雅关闭失败，使用强制终止:', error)
      }
      
      // 如果进程仍在运行，强制终止整个进程树
      if (this.backendProcess && !this.backendProcess.killed) {
        await this.killProcessTree(this.backendProcess.pid)
      }
      
      this.backendProcess = null
    }
    
    // 开发环境额外清理：清理可能占用端口的进程
    if (!app.isPackaged && process.platform === 'win32') {
      try {
        const { exec } = require('child_process')
        // 查找并清理占用常用端口的进程
        const ports = [3000, 3001, 8080, 8081, 9000] // 常见的开发服务器端口
        for (const port of ports) {
          exec(`netstat -ano | findstr :${port}`, (error, stdout) => {
            if (!error && stdout) {
              const lines = stdout.split('\n')
              lines.forEach(line => {
                const match = line.match(/\s+(\d+)$/)
                if (match) {
                  const pid = match[1]
                  exec(`taskkill /F /PID ${pid}`, (killError) => {
                    if (!killError) {
                      console.log(`已清理端口${port}上的进程 PID: ${pid}`)
                    }
                  })
                }
              })
            }
          })
        }
      } catch (error) {
        console.log('开发环境额外清理失败:', error)
      }
    }
    
    this.unregisterInstanceFromFile()
    console.log('后端服务已关闭，实例已注销。')
  }

  public getCurrentPorts(): PortConfig | null {
    return this.instanceInfo?.ports || null
  }

  // --- 进程管理 ---

  private spawnBackendProcess() {
    const isDev = !app.isPackaged;
    let command: string;
    let args: string[];
    let cwd: string | undefined;

    const exePath = path.join(process.cwd(), 'catl_server.exe');
    const catlDir = path.join(process.cwd(), '..', 'lora_server');

    if (!isDev || fs.existsSync(exePath)) {
      // 生产环境 或 存在exe的调试环境
      console.log('启动模式：生产环境 (exe)');
      command = exePath;
      args = [];
      cwd = path.dirname(exePath); // 确保工作目录是exe所在的目录
    } else {
      // 开发环境，并且没有exe
      console.log('启动模式：开发环境 (npm)');
      // 在Windows上，直接调用npm.cmd可以避免使用shell
      command = process.platform === 'win32' ? 'npm.cmd' : 'npm';
      args = ['run', 'dev'];
      cwd = catlDir;
    }

    // 确认后端目录存在
    if (!fs.existsSync(cwd)) {
        dialog.showErrorBox('启动错误', `后端工作目录不存在: ${cwd}`);
        return;
    }

    console.log('正在启动后端服务...', { command, args, cwd });
    // 关键：始终不使用shell，确保父子进程直接关联
    this.backendProcess = spawn(command, args, { 
        windowsHide: true, 
        shell: false, // 始终为 false
        cwd, 
        detached: false 
    });
    console.log(`后端服务进程已创建，PID: ${this.backendProcess.pid}`);
  }

  private setupProcessListeners() {
    if (!this.backendProcess) return
    this.backendProcess.on('spawn', () => {
      console.log('后端服务启动成功 (spawn event)')
      if (this.backendProcess?.pid) this.updateBackendPid(this.backendProcess.pid)
    })
    this.backendProcess.on('exit', (code, signal) => {
      console.log(`后端服务退出，退出码: ${code}, 信号: ${signal}`)
      if (this.instanceInfo && this.instanceInfo.backendPid) {
        console.log(`清理退出的后端进程 PID: ${this.instanceInfo.backendPid}`)
        this.instanceInfo.backendPid = null
      }
      this.backendProcess = null
      this.stopHealthMonitoring()
      if (!this.isStopping) this.restartBackend()
    })
    this.backendProcess.on('error', (err) => {
      console.error('后端服务启动出错:', err.message)
      this.stopHealthMonitoring()
      if (!this.isStopping) this.restartBackend()
    })
    this.backendProcess.stdout?.on('data', (data) => {
      const output = data.toString()
      console.log(`[Backend STDOUT]: ${output.trim()}`)
      this.handleBackendOutput(output)
    })
    this.backendProcess.stderr?.on('data', (data) => console.error(`[Backend STDERR]: ${data.toString().trim()}`))
  }

  private handleBackendOutput(output: string) {
    if (this.instanceInfo?.ports) return // 已获取，不再处理
    const portRegex = /{"masterPort":(\d+),"childPort":(\d+),"websocketPort":(\d+)/
    const match = output.match(portRegex)
    if (match) {
      const ports: PortConfig = {
        masterPort: parseInt(match[1], 10),
        childPort: parseInt(match[2], 10),
        websocketPort: parseInt(match[3], 10)
      }
      console.log('从后端服务检测到端口配置:', ports)
      this.updateInstanceWithPorts(ports)

      // --- 关键改动：立即主动推送到渲染进程 ---
      if (this.webContents && !this.webContents.isDestroyed()) {
        console.log('主动推送端口信息到渲染进程:', ports)
        this.webContents.send('server-ports-update', ports) // 使用新的事件名
      }
      // -----------------------------------------

      this.startHealthMonitoring()
    }
  }

  private async restartBackend() {
    if (this.isStopping || this.restartCount >= MAX_RESTART_ATTEMPTS) {
      if (this.restartCount >= MAX_RESTART_ATTEMPTS) dialog.showErrorBox('服务错误', `后端服务多次重启失败。`)
      return
    }
    const delay = BASE_RESTART_DELAY * Math.pow(2, this.restartCount++)
    console.log(`服务将在 ${delay / 1000} 秒后重启...`)
    setTimeout(() => {
      this.spawnBackendProcess()
      this.setupProcessListeners()
    }, delay)
  }

  // --- 健康检查 ---
  private startHealthMonitoring() {
    if (this.healthCheckTimer || !this.instanceInfo?.ports) return
    const portToCheck = this.instanceInfo.ports.masterPort
    console.log(`健康检查已启动 (Port: ${portToCheck})`)
    this.healthCheckTimer = setInterval(async () => {
      const isHealthy = await this.performHealthCheck(portToCheck)
      if (!isHealthy) {
        console.log('健康检查失败，准备重启服务...')
        this.stopHealthMonitoring()
        if (this.backendProcess && !this.backendProcess.killed) {
          await this.killProcessTree(this.backendProcess.pid)
        }
      }
    }, HEALTH_CHECK_INTERVAL)
  }

  private stopHealthMonitoring() {
    if (this.healthCheckTimer) {
      clearInterval(this.healthCheckTimer)
      this.healthCheckTimer = null
      console.log('健康检查已停止。')
    }
  }

  private async performHealthCheck(port: number): Promise<boolean> {
    return new Promise((resolve) => {
      const req = http.get(`http://127.0.0.1:${port}/socket/health`, { timeout: HEALTH_CHECK_TIMEOUT }, (res) => {
        console.log(`健康检查 ${port}`)
        resolve(res.statusCode === 200)
      })
      req.on('error', () => resolve(false))
      req.on('timeout', () => {
        req.destroy()
        resolve(false)
      })
    })
  }

  // --- 文件操作与实例注册 ---

  // --- 实例文件管理 (跨进程) ---
  private ensureFileExists(): void {
    if (!fs.existsSync(INSTANCE_FILE_PATH)) {
      this.writeInstanceFile({ instances: [], lastUpdated: new Date().toISOString() })
    }
  }

  private readInstanceFile(): InstanceFile {
    try {
      return JSON.parse(fs.readFileSync(INSTANCE_FILE_PATH, 'utf8'))
    } catch {
      return { instances: [], lastUpdated: new Date().toISOString() }
    }
  }

  private writeInstanceFile(data: InstanceFile) {
    fs.writeFileSync(INSTANCE_FILE_PATH, JSON.stringify(data, null, 2))
  }

  private cleanDeadInstances() {
    const data = this.readInstanceFile()
    const liveInstances = data.instances.filter(inst => this.isProcessRunning(inst.electronPid))
    if (liveInstances.length !== data.instances.length) {
      data.instances = liveInstances
      this.writeInstanceFile(data)
    }
  }

  private isProcessRunning(pid: number): boolean {
    try { process.kill(pid, 0); return true } catch { return false }
  }

  private registerInstance(): InstanceInfo | null {
    this.cleanDeadInstances()
    const data = this.readInstanceFile()
    if (data.instances.length >= MAX_INSTANCES) {
      console.warn(`实例数量已达上限 (${data.instances.length})，注册失败。`)
      return null
    }
    const newInstance: InstanceInfo = {
      electronPid: process.pid,
      backendPid: null,
      ports: null,
      startTime: new Date().toISOString()
    }
    data.instances.push(newInstance)
    this.writeInstanceFile(data)
    console.log(`成功注册实例 (PID: ${process.pid})，当前活跃实例: ${data.instances.length}`)
    return newInstance
  }

  private updateBackendPid(backendPid: number) {
    if (!this.instanceInfo) return
    this.instanceInfo.backendPid = backendPid
    const data = this.readInstanceFile()
    const index = data.instances.findIndex(inst => inst.electronPid === process.pid)
    if (index !== -1) {
      data.instances[index].backendPid = backendPid
      this.writeInstanceFile(data)
    }
  }
  
  private updateInstanceWithPorts(ports: PortConfig) {
      if (!this.instanceInfo) return
      this.instanceInfo.ports = ports
      const data = this.readInstanceFile()
      const index = data.instances.findIndex(inst => inst.electronPid === process.pid)
      if (index !== -1) {
        data.instances[index].ports = ports
        this.writeInstanceFile(data)
        console.log(`实例 (PID: ${this.instanceInfo.electronPid}) 已更新端口信息。`)
      }
  }

  private unregisterInstanceFromFile() {
    const data = this.readInstanceFile()
    const updatedInstances = data.instances.filter(inst => inst.electronPid !== process.pid)
    if (updatedInstances.length < data.instances.length) {
      data.instances = updatedInstances
      this.writeInstanceFile(data)
      console.log(`成功注销实例 (PID: ${process.pid})`)
    }
  }

  private killProcessTree(pid: number | undefined): Promise<void> {
    return new Promise(resolve => {
      if (!pid) return resolve()
      
      console.log(`正在终止进程树 PID: ${pid}`)
      
      if (process.platform === 'win32') {
        // Windows: 使用更强制的方式终止进程树
        const commands = [
          `taskkill /F /T /PID ${pid}`,  // 强制终止进程树
          `wmic process where "ParentProcessId=${pid}" delete`,  // 删除子进程
          `taskkill /F /PID ${pid}`  // 再次强制终止主进程
        ]
        
        let completed = 0
        const total = commands.length
        
        commands.forEach((command, index) => {
          exec(command, (error) => {
            if (error) {
              console.log(`命令 ${index + 1} 执行结果:`, error.message)
            } else {
              console.log(`命令 ${index + 1} 执行成功: ${command}`)
            }
            completed++
            if (completed === total) {
              // 额外等待确保进程完全终止
              setTimeout(() => {
                console.log(`进程树 PID: ${pid} 终止完成`)
                resolve()
              }, 1000)
            }
          })
        })
      } else {
        // Unix/Linux/macOS
        const command = `pkill -TERM -P ${pid} && kill -9 ${pid}`
        exec(command, (error) => {
          if (error) {
            console.log('Unix进程终止结果:', error.message)
          }
          resolve()
        })
      }
    })
  }
}

export const instanceManager = new InstanceManager()
